from typing import Optional, Tuple, Dict, Any
from pydantic import BaseModel, Field
import requests
import os
from enum import Enum
from dotenv import load_dotenv
import time
import urllib3
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# 加载环境变量
load_dotenv()


class DistanceMode(str, Enum):
    """距离计算模式"""
    STRAIGHT = "0"  # 直线距离
    DRIVING = "1"  # 驾车距离
    RIDING = "2"  # 骑行距离


# 配置信息
API_KEY = os.getenv("AMAP_MAPS_API_KEY")
MERCHANT_LONGITUDE = "115.845555"
MERCHANT_LATITUDE = "28.724572"
MERCHANT_LOCATION = f"{MERCHANT_LONGITUDE},{MERCHANT_LATITUDE}"  # 酱菜
DELIVERY_RADIUS = 5000  # 5 km
DEFAULT_DISTANCE_MODE = DistanceMode("2")  # 默认骑行距离


def create_session_with_retries():
    """创建带重试机制的requests会话"""
    session = requests.Session()

    # 配置重试策略
    retry_strategy = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504],
    )

    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("http://", adapter)
    session.mount("https://", adapter)

    return session


def safe_request(url: str, params: dict, max_retries: int = 3) -> Optional[dict]:
    """
    安全的HTTP请求，处理SSL和连接问题
    
    Args:
        url: 请求URL
        params: 请求参数
        max_retries: 最大重试次数
        
    Returns:
        响应数据或None
    """
    session = create_session_with_retries()

    for attempt in range(max_retries):
        try:
            # 先尝试HTTPS请求
            response = session.get(
                url,
                params=params,
                timeout=10,
                verify=False  # 跳过SSL验证
            )
            response.raise_for_status()
            return response.json()

        except requests.exceptions.SSLError:
            # SSL错误，尝试HTTP
            try:
                http_url = url.replace("https://", "http://")
                response = session.get(http_url, params=params, timeout=10)
                response.raise_for_status()
                return response.json()
            except Exception as e:
                print(f"HTTP请求也失败: {e}")

        except Exception as e:
            print(f"请求失败 (尝试 {attempt + 1}/{max_retries}): {e}")
            if attempt < max_retries - 1:
                time.sleep(1)  # 等待1秒后重试

    return None


def geocode_address(address: str) -> Optional[Tuple[str, str]]:
    """
    使用地理编码API将地址转换为坐标
    
    Args:
        address: 要转换的地址
        
    Returns:
        (location, formatted_address) 或 None
    """
    if not API_KEY:
        return None

    url = "https://restapi.amap.com/v3/geocode/geo"
    params = {
        "key": API_KEY,
        "address": address,
        "output": "json"
    }

    data = safe_request(url, params)
    if data and data["status"] == "1" and data["count"] != "0":
        geocode = data["geocodes"][0]
        return (
            geocode["location"],  # 经纬度坐标
            geocode["formatted_address"]  # 规范化后的地址
        )

    return None


def calculate_distance(origin: str, destination: str, mode: DistanceMode = DEFAULT_DISTANCE_MODE) -> Optional[float]:
    """
    使用距离测量API计算两点间距离（米）
    
    Args:
        origin: 起点坐标
        destination: 终点坐标
        mode: 距离计算模式
        
    Returns:
        距离（米）或 None
    """
    if not API_KEY:
        return None

    url = "https://restapi.amap.com/v3/distance"
    params = {
        "key": API_KEY,
        "origins": origin,
        "destination": destination,
        "type": mode.value
    }

    data = safe_request(url, params)
    if data and data["status"] == "1" and data["info"] == "OK":
        return float(data["results"][0]["distance"])
    elif data:
        print(
            f"距离计算API返回错误: status={data.get('status')}, info={data.get('info')}, infocode={data.get('infocode')}")

    return None


def check_delivery_range(address: str, mode: DistanceMode = DEFAULT_DISTANCE_MODE) -> Dict[str, Any]:
    """
    检查地址是否在配送范围内
    
    Args:
        address: 用户输入的地址
        mode: 距离计算模式
        
    Returns:
        包含检查结果的字典
    """
    if not API_KEY:
        return {
            "status": "error",
            "message": "地图服务未配置"
        }

    # 地理编码：将地址转换为坐标
    geocode_result = geocode_address(address)
    if not geocode_result:
        return {
            "status": "error",
            "message": "无法识别该地址"
        }

    user_location, formatted_address = geocode_result

    # 计算配送距离
    distance = calculate_distance(MERCHANT_LOCATION, user_location, mode)
    if distance is None:
        return {
            "status": "error",
            "message": "无法计算配送距离"
        }

    # 判断是否在配送范围内
    distance_km = distance / 1000
    in_range = distance <= DELIVERY_RADIUS

    return {
        "status": "success",
        "in_range": in_range,
        "distance": round(distance_km, 2),
        "formatted_address": formatted_address,
        "message": (
            f"配送地址：{formatted_address}\n"
            f"配送距离：{distance_km:.1f}公里\n"
            f"配送状态：{'在配送范围内' if in_range else '超出配送范围'}"
        )
    }


def get_merchant_location() -> str:
    """获取商户位置坐标"""
    return MERCHANT_LOCATION


def get_delivery_radius() -> int:
    """获取配送半径（米）"""
    return DELIVERY_RADIUS


def validate_config() -> bool:
    """验证配置是否完整"""
    return all([
        API_KEY,
        MERCHANT_LONGITUDE,
        MERCHANT_LATITUDE,
        DELIVERY_RADIUS > 0
    ])


# 请求模型
class DeliveryCheckRequest(BaseModel):
    """配送范围检查请求"""
    address: str = Field(..., description="用户输入的地址")
    mode: Optional[DistanceMode] = Field(
        default=DEFAULT_DISTANCE_MODE,
        description="距离计算模式：0-直线距离，1-驾车距离，2-骑行距离"
    )


# 响应模型
class DeliveryCheckResponse(BaseModel):
    """配送范围检查响应"""
    status: str = Field(..., description="请求状态")
    in_range: Optional[bool] = Field(None, description="是否在配送范围内")
    distance: Optional[float] = Field(None, description="距离（公里）")
    formatted_address: Optional[str] = Field(None, description="规范化后的地址")
    message: str = Field(..., description="返回消息")


def main():
    """主函数 - 测试高德地图工具功能"""
    print("=" * 50)
    print("高德地图工具测试")
    print("=" * 50)

    # 1. 验证配置
    print("\n1. 验证配置...")
    if validate_config():
        print("✅ 配置验证通过")
        print(f"   API密钥: {API_KEY[:10]}...")
        print(f"   商户位置: {get_merchant_location()}")
        print(f"   配送半径: {get_delivery_radius()}米")
    else:
        print("❌ 配置验证失败，请检查.env文件")
        return

    print("\n" + "=" * 50)
    print("测试完成")
    print("=" * 50)


if __name__ == "__main__":
    main()
